import { Provide, Inject, Config, Scope, ScopeEnum } from '@midwayjs/core';
import { CacheManager } from '@midwayjs/cache';
import * as svgCaptcha from 'svg-captcha';
import * as svgBase64 from 'mini-svg-data-uri';
import { FormulaCaptchaOptions, CaptchaOptions } from '../interface';
import { uuid } from '../../../utils/uuid';

/**
 * 验证码服务类
 * @Provide 标记为一个可以被注入的服务
 * @Scope(ScopeEnum.Singleton) 标记为单例模式，整个应用生命周期中只会创建一个实例
 */
@Provide()
@Scope(ScopeEnum.Singleton)
export class CaptchaService {
  /**
   * 注入缓存管理器，用于存储验证码
   */
  @Inject()
  cacheManager: CacheManager;

  /**
   * 注入验证码配置
   */
  @Config('captcha')
  captcha: CaptchaOptions;

  /**
   * 生成数学公式验证码
   * @param options 验证码生成选项
   * @returns 返回验证码ID和Base64格式的图片数据
   */
  async formula(options?: FormulaCaptchaOptions) {
    // 创建数学表达式验证码
    const { data, text } = svgCaptcha.createMathExpr(options);
    // 保存验证码答案并获取ID
    const id = await this.set(text);
    // 将SVG转换为Base64格式
    const imageBase64 = svgBase64(data);
    return { id, imageBase64 };
  }

  /**
   * 保存验证码文本到缓存
   * @param text 验证码文本（答案）
   * @returns 返回验证码唯一标识
   */
  async set(text: string): Promise<string> {
    const id = uuid();
    // 将验证码答案存入缓存，并设置过期时间
    await this.cacheManager.set(
      this.getStoreId(id),
      (text || '').toLowerCase(),
      { ttl: this.captcha.expirationTime }
    );
    return id;
  }

  /**
   * 校验验证码是否正确
   * @param id 验证码ID
   * @param value 用户输入的答案
   * @returns 返回验证结果
   */
  async check(id: string, value: string): Promise<boolean> {
    if (!id || !value) {
      return false;
    }
    const storeId = this.getStoreId(id);
    // 从缓存中获取正确答案
    const storedValue = await this.cacheManager.get(storeId);
    // 比较用户输入与正确答案（不区分大小写）
    if (value.toLowerCase() !== storedValue) {
      return false;
    }
    // 验证成功后删除缓存中的验证码
    this.cacheManager.del(storeId);
    return true;
  }

  /**
   * 生成缓存中的验证码ID
   * @param id 原始ID
   * @returns 添加了前缀的完整ID
   */
  private getStoreId(id: string): string {
    if (!this.captcha.idPrefix) {
      return id;
    }
    return `${this.captcha.idPrefix}:${id}`;
  }
}
